package com.clp.protocol.iec104.iec104.server.slavechannel.pipeline;

import com.clp.protocol.iec104.iec104.apdu.IAsduFactory;
import com.clp.protocol.iec104.iec104.apdu.asdu.IAsdu;
import com.clp.protocol.iec104.iec104.apdu.asdu.infoobj.InfoObj;
import com.clp.protocol.iec104.iec104.definition.cot.Pn;
import com.clp.protocol.iec104.iec104.definition.quatype.InitCauseQuaType;
import com.clp.protocol.iec104.iec104.server.slavechannel.InSlaveChannel;
import com.clp.protocol.iec104.iec104.server.slavechannel.SlaveChannelIAsduSender;
import com.clp.protocol.iec104.iec104.server.slavechannel.pipeline.state.data.TotalCall100DataReactor;
import com.clp.protocol.iec104.iec104.server.slavechannel.pipeline.state.data.TotalCall101DataReactor;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;

import java.util.List;

public class InternalIAsduSender implements SlaveChannelIAsduSender {
    private final PipelineManager manager;
    private final AsduSendEntrance entrance;

    public InternalIAsduSender(PipelineManager manager, AsduSendEntrance entrance) {
        this.manager = manager;
        this.entrance = entrance;
    }

    @Override
    public InSlaveChannel slaveChannel() {
        return manager.getInSlaveChannel();
    }

    public ChannelFuture chSend(IAsdu iAsdu) {
        ChannelPromise promise = newChannelPromise();
        safeExecute(() -> entrance.tryChannelSend(iAsdu, promise));
        return promise;
    }

    private ChannelPromise newChannelPromise() {
        return slaveChannel().channel().newPromise();
    }

    private void safeExecute(Runnable task) {
        slaveChannel().executor().execute(task);
    }

    private int rtuAddr() {
        return manager.getInSlaveChannel().slave().rtuAddr();
    }

    /********************************************* chSend ******************************************************/
    public ChannelFuture chSendInitCompleted(InitCauseQuaType quaType) {
        return chSend(IAsduFactory.getIAsduOfInitCompleted(rtuAddr(), quaType));
    }

    /**
     * 发送总召唤确认
     * @param pn
     * @return
     */
    public ChannelFuture chSendTotalCall100Ack(Pn pn) {
        return chSend(IAsduFactory.getIAsduOfTotalCall100Ack(rtuAddr(), pn));
    }

    public ChannelFuture chSendTotalCall100TmData(TotalCall100DataReactor.TmDataType tmDataType, List<InfoObj> infoObjs) {
        switch (tmDataType) {
            case FLOAT:
                return chSendTotalCall100TmDataFloat(infoObjs);
        }
        throw new UnsupportedOperationException();
    }

    private ChannelFuture chSendTotalCall100TmDataFloat(List<InfoObj> cInfoObjs) {
        return chSend(IAsduFactory.getIAsduOfTotalCall100TmDataFloat(rtuAddr(), cInfoObjs));
    }

    public ChannelFuture chSendTotalCall100TsData(TotalCall100DataReactor.TsDataType tsDataType, List<InfoObj> infoObjs) {
        switch (tsDataType) {
            case ONE_POINT:
                return chSendTotalCall100TsDataOnePoint(infoObjs);
            case TWO_POINT:
                return chSendTotalCall100TsDataTwoPoint(infoObjs);
        }
        throw new UnsupportedOperationException();
    }

    private ChannelFuture chSendTotalCall100TsDataOnePoint(List<InfoObj> infoObjs) {
        return chSend(IAsduFactory.getIAsduOfTotalCall100TsDataOnePoint(rtuAddr(), infoObjs));
    }

    private ChannelFuture chSendTotalCall100TsDataTwoPoint(List<InfoObj> infoObjs) {
        return chSend(IAsduFactory.getIAsduOfTotalCall100TsDataTwoPoint(rtuAddr(), infoObjs));
    }

    public ChannelFuture chSendTotalCall100Finished() {
        return chSend(IAsduFactory.getIAsduOfTotalCall100Finished(rtuAddr()));
    }

    public ChannelFuture chSendTotalCall101Ack(Pn pn) {
        return chSend(IAsduFactory.getIAsduOfTotalCall101Ack(rtuAddr(), pn));
    }

    public ChannelFuture chSendTotalCall101TpData(TotalCall101DataReactor.TpDataType tpDataType, List<InfoObj> infoObjs) {
        switch (tpDataType) {
            case CUMULANT:
                return chSendTotalCall101TpDataCumulant(infoObjs);
        }
        throw new UnsupportedOperationException();
    }

    public ChannelFuture chSendTotalCall101TpDataCumulant(List<InfoObj> infoObjs) {
        return chSend(IAsduFactory.getIAsduOfTotalCall101DataCumulant(rtuAddr(), infoObjs));
    }

    public ChannelFuture chSendTotalCall101Finished() {
        return chSend(IAsduFactory.getIAsduOfTotalCall101Finished(rtuAddr()));
    }
}
